<?php

namespace App\Http\Controllers\Api;

use App\Constant;
use App\Enums\AuditStatus;
use App\Enums\LoginMode;
use App\Enums\WalletStatus;
use App\Events\UserAuthed;
use App\Events\UserRegistered;
use App\Exceptions\ApiException;
use App\Http\Controllers\Controller;
use App\Models\AgentConfig;
use App\Models\Channel;
use App\Models\FrontendUser;
use App\Models\LoginHistory;
use App\Models\UserAuth;
use App\Models\UserWallet;
use App\Services\SdPayService;
use App\Services\VerifyCodeService;
use App\Services\WalletService;
use App\Services\XunChengService;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;

class UserController extends Controller
{
    /** @var WalletService */
    private $walletService;

    /** @var VerifyCodeService */
    private $verifyCodeService;

    /** @var XunChengService */
    private $xcService;

    /**
     * UserController constructor.
     */
    public function __construct(WalletService $walletService, VerifyCodeService $verifyCodeService, XunChengService $xcService)
    {
        $this->walletService = $walletService;
        $this->verifyCodeService = $verifyCodeService;
        $this->xcService = $xcService;
    }

    /** 发送短信验证码 */
    public function verifyCode()
    {
        request()->validate([
            'mobile' => 'required',
        ]);
        $mobile = request()->mobile;
        $this->verifyCodeService->send($mobile);
    }

    /** 用户注册 */
    public function register()
    {
        request()->validate([
            'mobile' => 'required',
            'verify_code' => 'required',
            'password' => 'required',
            'channel' => 'nullable',
            'invitor_mobile' => 'nullable',
            'invitor_id' => 'nullable',
        ]);

        $mobile = request()->mobile;
        $verifyCode = request()->verify_code;
        $this->verifyCodeService->check($mobile, $verifyCode);

        $configs = AgentConfig::query()->where('agent_id', request()->agent_id)
            ->whereIn('config_key', [AgentConfig::CHANNEL_REGISTER_ONLY, AgentConfig::DAILY_REGISTER_LIMIT])
            ->pluck('config_value', 'config_key');

        //检查每日注册数量限制
        $dailyRegisterLimit = Arr::get($configs, AgentConfig::DAILY_REGISTER_LIMIT, -1);
        if (0 == $dailyRegisterLimit) {
            throw new ApiException('平台暂未开放注册');
        }
        if ($dailyRegisterLimit > 0) {
            $todayRegisterCount = FrontendUser::query()->where('agent_id', request()->agent_id)
                ->whereDate('created_at', today()->toDateString())
                ->count();
            if ($todayRegisterCount >= $dailyRegisterLimit) {
                throw new ApiException('已达今日最大注册人数');
            }
        }
        $walletAddress = $this->walletService->openWallet($mobile);
        $existed = FrontendUser::query()
            ->where('mobile', $mobile)
            ->where('agent_id', request()->agent_id)
            ->first();
        if ($existed) {
            throw new ApiException('用户已存在');
        }
        $user = new FrontendUser();
        $user->mobile = $mobile;
        $user->agent_id = request()->agent_id;
        $user->password = \Hash::make(request()->password);
        $user->wallet_address = $walletAddress;
        // 检查渠道码注册限制
        $channelRegisterOnly = Arr::get($configs, AgentConfig::CHANNEL_REGISTER_ONLY, 0);
        if (1 == $channelRegisterOnly && !request()->channel) {
            throw new ApiException('请通过专属渠道注册');
        }
        $channel = null;
        if (request()->channel) {
            /** @var Channel $channel */
            $channel = Channel::query()->where('uuid', request()->channel)->first();
            if (!$channel) {
                throw new ApiException('无效的渠道码');
            }
            $todayChannelRegisterCount = FrontendUser::query()
                ->where('agent_id', request()->agent_id)
                ->where('channel_id', $channel->id)
                ->whereDate('created_at', today()->toDateString())
                ->count();
            if ($channel->daily_register_limit > 0 && $todayChannelRegisterCount >= $channel->daily_register_limit) {
                throw new ApiException('该渠道已达今日最大注册人数');
            }
        }
        if (request()->invitor_mobile) {
            $invitor = FrontendUser::query()
                ->where('agent_id', request()->agent_id)
                ->where('mobile', request()->invitor_mobile)->first();
            if ($invitor) {
                $user->parent_id = $invitor->id;
            }
        } else {
            if (request()->invitor_id) {
                /** @var FrontendUser $invitor */
                $invitor = FrontendUser::query()
                    ->where('agent_id', request()->agent_id)
                    ->where('id', request()->invitor_id)->first();
                if ($invitor) {
                    $user->parent_id = $invitor->id;
                }
            }
        }
        $user->channel_id = $channel ? $channel->id : 0;
        $user->save();
        UserRegistered::dispatch($user);

        return $this->doLogin($user, LoginMode::REGISTER(), $user->channel_id);
    }

    /** 重置密码 */
    public function resetPassword()
    {
        request()->validate([
            'mobile' => 'required',
            'verify_code' => 'required',
            'password' => 'required',
        ]);

        $mobile = request()->mobile;
        $verifyCode = request()->verify_code;
        $this->verifyCodeService->check($mobile, $verifyCode);

        $user = FrontendUser::query()
            ->where('mobile', $mobile)
            ->where('agent_id', request()->agent_id)
            ->first();
        if (!$user) {
            throw new ApiException('手机号未注册');
        }
        $user->password = Hash::make(request()->password);
        $user->save();
    }

    /** 修改密码 */
    public function changePassword()
    {
        request()->validate([
            'old_password' => 'required',
            'new_password' => 'required',
        ]);

        /** @var FrontendUser $user */
        $user = auth()->user();
        if (!Hash::check(request()->old_password, $user->password)) {
            throw new ApiException('旧密码不正确');
        }
        $user->password = Hash::make(request()->new_password);
        $user->save();
    }

    /** 设置二级密码 */
    public function setSecondPassword()
    {
        request()->validate([
            'verify_code' => 'required',
            'second_pass' => 'required | digits:6',
        ], [
            'second_pass.digits' => '密码长度必须为六位数字',
        ]);

        /** @var FrontendUser $user */
        $user = auth()->user();
        $verifyCode = request()->verify_code;
        $this->verifyCodeService->check($user->mobile, $verifyCode);

        $user->second_pass = Hash::make(request()->second_pass);
        $user->save();
    }

    /** 登录 */
    public function login()
    {
        request()->validate([
            'mobile' => 'required',
            'password' => 'nullable',
            'verify_code' => 'nullable',
            'channel' => 'nullable',
        ]);
        $mobile = request()->mobile;
        $user = FrontendUser::query()
            ->where('mobile', $mobile)
            ->where('agent_id', request()->agent_id)
            ->first();
        if (!$user) {
            throw new ApiException('用户未注册');
        }
        $password = request()->password;
        $verifyCode = request()->verify_code;
        if ($password) {
            $loginMode = LoginMode::PASSWORD();
            if (!Hash::check($password, $user->password)) {
                throw new ApiException('密码错误');
            }
        } elseif ($verifyCode) {
            $loginMode = LoginMode::VERIFY_CODE();
            $this->verifyCodeService->check($mobile, $verifyCode);
        } else {
            throw new ApiException('请输入登录密码或短信验证码');
        }
        $channelId = Channel::query()->where('uuid', request()->channel)->value('id') ?: 0;

        return $this->doLogin($user, $loginMode, $channelId);
    }

    /** 快速登录接口，手机号不存在则自动注册 */
    public function loginOrRegister()
    {
        request()->validate([
            'mobile' => 'required',
            'verify_code' => 'required',
            'channel' => 'nullable',
            'invitor_mobile' => 'nullable',
        ]);

        $mobile = request()->mobile;
        $verifyCode = request()->verify_code;
        $this->verifyCodeService->check($mobile, $verifyCode);

        $channelId = Channel::query()->where('uuid', request()->channel)->value('id') ?: 0;
        $user = FrontendUser::query()
            ->where('mobile', $mobile)
            ->where('agent_id', request()->agent_id)
            ->first();
        if (!$user) {
            $walletAddress = $this->walletService->openWallet($mobile);
            $user = new FrontendUser();
            $user->mobile = $mobile;
            $user->agent_id = request()->agent_id;
            $user->password = '';
            $user->wallet_address = $walletAddress;
            if (request()->invitor_mobile) {
                $invitor = FrontendUser::query()
                    ->where('agent_id', request()->agent_id)
                    ->where('mobile', request()->invitor_mobile)->first();
                if ($invitor) {
                    $user->parent_id = $invitor->id;
                }
            }
            $user->channel_id = $channelId;
            $user->save();
            UserRegistered::dispatch($user);
        }

        return $this->doLogin($user, LoginMode::VERIFY_CODE_FAST(), $channelId);
    }

    /** 查询个人信息 */
    public function getProfile()
    {
        /** @var FrontendUser $user */
        $user = auth()->user();
        $channel = Channel::query()->where('agent_id', request()->agent_id)
            ->where('mobile', $user->mobile)->first();
        $result = [
            'id' => $user->id,
            'mobile' => $user->mobile,
            'nickname' => $user->nickname ?: '',
            'avatar_url' => $user->avatar_url ?: '',
            'wallet_address' => $user->wallet_address,
            'channel_id' => $channel ? $channel->id : '0',
        ];
        if ($user->auth) {
            $result['real_name'] = [
                'real_name' => $user->auth->real_name,
                'audit_status' => $user->auth->audit_status->value,
                'reject_reason' => $user->auth->reject_reason,
            ];
        }
        $resaleEnabled = AgentConfig::getConfig(request()->agent_id, AgentConfig::WEBSITE_ENABLE_RESALE, false);
        if ($resaleEnabled) {
            $wallet = $user->wallet;
            $result['show_wallet_entry'] = 1;
            $result['user_wallet_status'] = ($wallet ? $wallet->status : WalletStatus::NOT_PAY())->value;
            $openWalletFee = AgentConfig::getConfig(request()->agent_id, AgentConfig::OPEN_WALLET_FEE, '0');
            $result['open_wallet_fee'] = '' == $openWalletFee ? '0' : $openWalletFee;
        }

        return $result;
    }

    /** 修改个人信息 */
    public function saveProfile()
    {
        $params = request()->validate([
            'nickname' => 'nullable',
            'avatar_url' => 'nullable',
        ]);

        /** @var FrontendUser $user */
        $user = auth()->user();
        $user->fill($params);
        $user->save();
    }

    /** 获取开通钱包的地址 */
    public function getWalletUrl()
    {
        /** @var FrontendUser $user */
        $user = auth()->user();

        $agentConfigs = AgentConfig::listConfigsByAgentId(request()->agent_id);
        $openWalletFee = Arr::get($agentConfigs, AgentConfig::OPEN_WALLET_FEE, 0);
        $wallet = $user->wallet;
        if (!$wallet) {
            $wallet = new UserWallet();
            $wallet->merchant_no = Arr::get($agentConfigs, AgentConfig::SDPAY_MERCH_NO);
            $wallet->user_id = $user->id;
            $wallet->wallet_user_no = $user->mobile;
            $wallet->status = WalletStatus::NOT_PAY;
        }
        if ($wallet->status->is(WalletStatus::NOT_PAY) && $openWalletFee <= 0) {
            $wallet->status = WalletStatus::PAID;
        }
        $wallet->save();

        $sdpayService = new SdPayService($agentConfigs);
        $redirectUrl = request()->redirect_url;
        if ($wallet->status->is(WalletStatus::NOT_PAY)) {
            $orderNo = 'WALLET_' . $user->mobile . '_' . time();

            return [
                'wallet_url' => $sdpayService->getUnionPayLink(
                    $orderNo,
                    $openWalletFee,
                    '钱包服务费' . $openWalletFee . '元',
                    md5($user->mobile),
                    '',
                    $redirectUrl,
                    now()->addMinutes(10)
                ),
            ];
        }

        return [
            'wallet_url' => $sdpayService->getWalletUrl($wallet, $redirectUrl),
        ];
    }

    /** 查询实名认证信息 */
    public function getRealName()
    {
        /** @var FrontendUser $user */
        $user = auth()->user();
        $auth = $user->auth;
        if (!$auth) {
            return [];
        }

        return [
            'real_name' => $auth->real_name,
            'id_card' => $auth->id_card,
            'id_card_front_image' => $auth->id_card_front_image,
            'id_card_back_image' => $auth->id_card_back_image,
            'province' => $auth->province,
            'city' => $auth->city,
            'district' => $auth->district,
            'address' => $auth->address,
            'bank_card_no' => $auth->bank_card_no,
            'bank_code' => $auth->bank_code,
            'bank_card_mobile' => $auth->bank_card_mobile,
            'audit_status' => $auth->audit_status->value,
            'reject_reason' => $auth->reject_reason,
        ];
    }

    /** 保存实名认证信息 */
    public function saveRealName()
    {
        $params = request()->validate([
            'real_name' => 'required',
            'id_card' => 'required',
            'id_card_front_image' => 'required',
            'id_card_back_image' => 'required',
            'province' => 'required',
            'city' => 'required',
            'district' => 'required',
            'address' => 'required',
            'bank_card_no' => 'required',
            'bank_code' => 'required',
            'bank_card_mobile' => 'required',
            'verify_code' => 'required',
        ]);
        $this->verifyCodeService->check(request()->bank_card_mobile, request()->verify_code);

        /** @var FrontendUser $user */
        $user = auth()->user();
        $auth = $user->auth;
        if (!$auth) {
            $auth = new UserAuth();
            $auth->user_id = $user->id;
        }
        $auth->fill($params);
        $auth->merchant_no = '';
        $auth->reject_reason = '';
        $auth->audit_status = AuditStatus::WAITING();
        $auth->save();

        $authParams = $auth->toArray();
        // 上传资质图片
        $authParams['id_card_front_image'] = $this->sdpayService->upload($auth->id_card_front_image);
        $authParams['id_card_back_image'] = $this->sdpayService->upload($auth->id_card_back_image);

        // 开通小微商户
        try {
            $requestNo = $this->sdpayService->microRegister($authParams);
            $auth->yeepay_request_no = $requestNo;
            $auth->save();
        } catch (\Exception $e) {
            $auth->audit_status = AuditStatus::REJECT;
            $auth->reject_reason = '认证请求提交失败: ' . $e->getMessage();
            $auth->save();

            throw new ApiException($e->getMessage());
        }
    }

    /** 身份证实名 */
    public function saveIdCardImage()
    {
        request()->validate([
            'id_card_front_image' => 'required',
            'id_card_back_image' => 'required',
        ]);

        $this->xcService->setAgentId(request()->agent_id);

        try {
            $frontOcr = $this->xcService->idCardFrontOcr(base64_encode(file_get_contents(request()->id_card_front_image)));
        } catch (\Exception $e) {
            throw new ApiException('身份证图片识别失败:' . $e->getMessage());
        }

        $ocrName = Arr::get($frontOcr, 'name');
        $ocrNo = Arr::get($frontOcr, 'num');
        $ocrAddress = Arr::get($frontOcr, 'address');
        $this->doSaveIdCard($ocrName, $ocrNo, $ocrAddress, request()->id_card_front_image, request()->id_card_back_image);
    }

    public function saveIdCard()
    {
        request()->validate([
            'name' => 'required',
            'id_card' => 'required',
        ]);
        $this->xcService->setAgentId(request()->agent_id);
        $this->doSaveIdCard(request()->name, request()->id_card);
    }

    /** 绑定/修改银行卡 */
    public function saveBankCard()
    {
        request()->validate([
            'bank_card_no' => 'required',
            'bank_code' => 'required',
            'bank_card_mobile' => 'required',
            'verify_code' => 'required',
        ]);

        /** @var FrontendUser $user */
        $user = auth()->user();
        $auth = $user->auth;
        if (!$auth) {
            throw new ApiException('用户未实名');
        }
        $bankCardNo = request()->bank_card_no;
        $bankCode = request()->bank_code;
        $bankCardMobile = request()->bank_card_mobile;
        $this->verifyCodeService->check($bankCardMobile, request()->verify_code);
        if ($auth->audit_status->isNot(AuditStatus::PASS())) {
            request()->validate([
                'province' => 'nullable',
                'city' => 'nullable',
                'district' => 'nullable',
            ]);
            $auth->province = request()->province;
            $auth->city = request()->city;
            $auth->district = request()->district;
            $auth->bank_card_no = $bankCardNo;
            $auth->bank_code = $bankCode;
            $auth->bank_card_mobile = $bankCardMobile;
            $auth->audit_status = AuditStatus::WAITING();
            $auth->reject_reason = '';
            //绑定银行卡
            $authParams = $auth->toArray();
            // 上传资质图片
            $authParams['id_card_front_image'] = $this->sdpayService->upload($auth->id_card_front_image);
            $authParams['id_card_back_image'] = $this->sdpayService->upload($auth->id_card_back_image);
            // 开通小微商户
            try {
                $requestNo = $this->sdpayService->microRegister($authParams);
                $auth->yeepay_request_no = $requestNo;
                $auth->save();
            } catch (\Exception $e) {
                $auth->audit_status = AuditStatus::REJECT;
                $auth->reject_reason = '认证请求提交失败: ' . $e->getMessage();
                $auth->save();

                throw new ApiException($e->getMessage());
            }
        } else {
            //更换银行卡
            $auth->bank_card_no = $bankCardNo;
            $auth->bank_code = $bankCode;
            $auth->bank_card_mobile = $bankCardMobile;

            try {
                $this->sdpayService->addMerchantCard($auth->merchant_no, $bankCardNo, $bankCode);
            } catch (\Exception $e) {
                throw new ApiException('换卡失败:' . $e->getMessage());
            }
            $auth->save();
        }
    }

    public function checkWalletAddress()
    {
        set_time_limit(0);
        $fontend_user = FrontendUser::where('wallet_address', '')->limit(500)->get();

        foreach ($fontend_user as $k => $v) {
            if (empty($v->password)) {
                $v->password = Hash::make('123456');
            }

            $v->wallet_address = $this->walletService->openWallet($v->mobile);

            $v->save();
        }
    }

    private function doSaveIdCard($name, $cardNo, $address = '', $frontImageUrl = '', $backImageUrl = '')
    {
        /** @var FrontendUser $user */
        $user = auth()->user();
        $auth = $user->auth;
        if ($auth) {
            throw new ApiException('您已经完成实名认证，请不要重复提交');
        }
        $birth = Carbon::parse(substr($cardNo, 6, 8))->format('Y-m-d');
        $existAuth = UserAuth::query()
            ->where('id_card', $cardNo)
            ->whereHas('user', function ($q) {
                return $q->where('agent_id', request()->agent_id);
            })->first();
        if ($existAuth && $existAuth->user_id != $user->id) {
            throw new ApiException('该身份证已被其他人使用');
        }

        $diffYear = Carbon::now()->diffInYears($birth);

        if ($diffYear < 18 || $diffYear > 60) {
            throw new ApiException('仅支持18-60岁用户实名');
        }

        try {
            $authResult = $this->xcService->realNameAuth($cardNo, $name);
        } catch (\Exception $e) {
            throw new ApiException('实名认证失败:' . $e->getMessage());
        }

        if (!$auth) {
            $auth = new UserAuth();
            $auth->user_id = $user->id;
        }
        $auth->id_card_front_image = $frontImageUrl;
        $auth->id_card_back_image = $backImageUrl;
        $auth->real_name = $name;
        $auth->id_card = $cardNo;
        $auth->province = '';
        $auth->city = '';
        $auth->district = '';
        $auth->address = $address;
        $auth->bank_code = '';
        $auth->bank_card_no = '';
        $auth->bank_card_mobile = '';
        $auth->reject_reason = '';
        $auth->audit_status = AuditStatus::NOT_SUBMIT;
        $auth->save();
        UserAuthed::dispatch($user);
    }

    /** 执行登录操作 */
    private function doLogin(FrontendUser $user, LoginMode $mode, $channelId = 0)
    {
        $token = Auth::guard(Constant::GUARD_API)->login($user);
        $user->last_login_time = now();
        $user->save();
        $userInfo = [
            'user_id' => $user->id,
            'nickname' => $user->nickname ?: $user->mobile,
            'avatar_url' => $user->avatar_url ?: '',
        ];
        if ($user->auth) {
            $userInfo['real_name'] = $user->auth->real_name;
        }
        //记录登录历史
        $history = new LoginHistory();
        $history->user_id = $user->id;
        $history->login_mode = $mode->value;
        $history->channel_id = $channelId;
        $history->save();

        return [
            'access_token' => $token,
            'user_info' => $userInfo,
        ];
    }
}
